<template>
  <div class="user-manual">
    <h1>重明—以太坊虚拟机安全检测平台使用帮助</h1>
    <p>欢迎使用重明—以太坊虚拟机安全检测平台。本页面将指导您如何使用该平台的主要功能，以便帮助您检测EVM（Ethereum Virtual Machine）实现中的潜在安全问题。</p>

    <h2>• 1. 平台架构图</h2>
    <div class="image-container">
      <img src="../../assets/logo/56.png" alt="平台架构图">
    </div>

    <h2>• 2. 操作步骤</h2>

    <h3>• 2.1 测试用例生成</h3>
    <p>在“测试用例生成”页面，用户可以通过LLM辅助生成多样化测试用例。</p>
    <ul>
      <li><strong>生成策略：</strong>选择生成策略，包括随机生成、变异生成。</li>
      <li><strong>调用的模型：</strong>可以选择不同的大语言模型来辅助生成字节码测试用例。</li>
      <li><strong>控制流图：</strong>点击“查看控制流图”可以查看操作码的控制流图，帮助理解操作码的执行逻辑。</li>
    </ul>

    <h3>• 2.2 测试执行控制台</h3>
    <p>在“测试执行控制台”页面，您可以选择EVM实现和设置测试次数。</p>
    <ul>
      <li><strong>支持的EVM：</strong>选择您想要对比的EVM实现，支持Geth、Besu、Py-EVM、EthereumJS等。</li>
      <li><strong>测试次数：</strong>设置测试用例的执行次数，范围在1到100次。</li>
      <li><strong>字节码输入：</strong>可以在“字节码测试用例”输入框中手动输入字节码，或者使用之前生成的字节码测试用例。</li>
      <li><strong>开始测试：</strong>点击“开始测试”按钮，平台会在不同的EVM实现中执行测试用例，并展示测试进度。</li>
    </ul>

    <h3>• 2.3 测试进度与覆盖率</h3>
    <p>在测试执行过程中，您可以查看实时的测试进度，并跟踪测试覆盖率。</p>
    <ul>
      <li><strong>测试进度：</strong>测试执行时，进度条会显示当前测试的进度。</li>
      <li><strong>覆盖率展示：</strong>测试完成后，函数级和包级的覆盖率会以百分比形式展示，帮助用户了解测试覆盖的程度。</li>
    </ul>

    <h3>• 2.4 检测与分析</h3>
    <p>当测试完成后，平台会比较不同EVM实现的执行结果并展示差异。</p>
    <ul>
      <li><strong>测试结果：</strong>每个EVM实现的测试结果会显示，包括EVM名称、测试结果（通过/失败）、Gas消耗、堆栈状态和存储状态。</li>
      <li><strong>不一致性分析：</strong>如果检测到EVM实现间的差异，平台会给出不一致的操作码和原因，并展示详细的运行时信息（如程序计数器、堆栈和内存状态）。</li>
    </ul>

    <h2>• 3. 常见问题与解答</h2>

    <h3>• 3.1 如何生成有效的测试用例？</h3>
    <p>平台通过大语言模型辅助生成测试用例，确保生成的字节码具有语义有效性。您可以选择不同的生成策略来调整测试用例的多样性，包括随机生成、边界值生成等。</p>

    <h3>• 3.2 如何检测EVM实现间的差异？</h3>
    <p>差分测试会自动对比不同EVM实现的执行结果，使用三种一致性评估指标（返回数据、Gas消耗、存储变更）来识别不一致性，平台会生成详细的差异报告。</p>

    <h3>• 3.3 如何解读报告？</h3>
    <p>报告中会展示导致不一致的操作码、堆栈和内存状态变化、Gas消耗等信息，帮助您快速定位问题。</p>

    <h2>• 4. EELS 规范</h2>
    <p>以下是EVM堆栈指令的实现部分，使用Python语言实现，描述了EVM在执行过程中的堆栈操作。</p>
    <p>
      EELS（Ethereum Execution Layer Specification）规范主要描述了以太坊虚拟机（EVM）堆栈操作的实现细节。通过这些指令的实现，开发者可以了解EVM在执行过程中如何处理堆栈操作、如何进行Gas计费，以及如何在程序计数器（Program Counter, PC）上进行操作。这些堆栈指令在EVM执行字节码时非常关键。
    </p>

    <h3>• 4.1 EVM 堆栈指令实现的概述</h3>
    <p>
      该规范的实现部分展示了如何处理EVM中的堆栈指令，比如弹出、压入、复制和交换堆栈元素。主要指令包括：
    </p>
    <ul>
      <li><strong>pop：</strong>从堆栈顶部弹出一个元素。</li>
      <li><strong>push_n：</strong>将指定大小的字节（<code>num_bytes</code>）从EVM代码中读取，并压入堆栈。支持不同大小的push操作（<code>push0</code> 到 <code>push32</code>）。</li>
      <li><strong>dup_n：</strong>复制堆栈中第n个元素到堆栈顶部。支持从 <code>dup1</code> 到 <code>dup16</code>。</li>
      <li><strong>swap_n：</strong>交换堆栈顶部元素和第n个元素，支持从 <code>swap1</code> 到 <code>swap16</code>。</li>
    </ul>

    <h3>• 4.2 Gas 计费</h3>
    <p>
      每个操作都需要消耗Gas，这是EVM的一项重要特性，用来防止无限循环以及确保网络资源的有效利用。规范中详细描述了如何为不同操作指令进行Gas计费，比如：
    </p>
    <ul>
      <li><strong>GAS_BASE：</strong>基础Gas消耗。</li>
      <li><strong>GAS_VERY_LOW：</strong>对于低消耗操作的Gas费用。</li>
    </ul>

    <h3>• 4.3 程序计数器（PC）操作</h3>
    <p>
      在执行每个操作时，程序计数器会移动到下一个指令。规范中展示了如何根据不同指令更新PC。例如：
    </p>
    <ul>
      <li><code>evm.pc += Uint(1)</code>：通常情况下，指令执行后PC前进1位（表示到达下一个字节码指令）。</li>
      <li><code>evm.pc += Uint(1) + Uint(num_bytes)</code>：对于需要读取多个字节的push操作，PC根据读取字节数来更新。</li>
    </ul>

    <h3>• 4.4 错误处理</h3>
    <p>
      在执行堆栈操作时，如果堆栈中的元素不足，规范中会抛出<code>StackUnderflowError</code>，以确保程序能够正确处理异常情况。
    </p>

    <h3>• 4.5 简化与重复操作的实现</h3>
    <p>
      通过使用<code>partial</code>函数来简化代码。例如，<code>push_n</code>、<code>dup_n</code>和<code>swap_n</code>通过<code>partial</code>来创建不同的push、dup和swap操作，从而减少代码重复。
    </p>

    <h3>• 4.6 指令函数的实现</h3>
    <p>
      规范中定义了具体的堆栈操作指令，如：
    </p>
    <ul>
      <li><code>push0</code> 到 <code>push32</code>：表示将0到32字节数据压入堆栈。</li>
      <li><code>dup1</code> 到 <code>dup16</code>：表示复制堆栈中的第1到第16个元素到堆栈顶部。</li>
      <li><code>swap1</code> 到 <code>swap16</code>：表示交换堆栈顶部元素与第1到第16个元素。</li>
    </ul>

    <h3>• 4.7 总结</h3>
    <p>
      EELS规范描述了EVM堆栈指令的具体实现方式，包括堆栈操作、Gas计费、错误处理以及程序计数器的更新等。这些实现为EVM的运行提供了核心支持，帮助开发者深入理解EVM的底层执行逻辑。
    </p>

    <pre>
      <code>
        """
        Ethereum Virtual Machine (EVM) Stack Instructions
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

        Implementations of the EVM stack related instructions.
        """

        from functools import partial

        from ethereum_types.numeric import U256, Uint

        from .. import Evm, stack
        from ..exceptions import StackUnderflowError
        from ..gas import GAS_BASE, GAS_VERY_LOW, charge_gas
        from ..memory import buffer_read

        def pop(evm: Evm) -> None:
            stack.pop(evm.stack)
            charge_gas(evm, GAS_BASE)
            evm.pc += Uint(1)

        def push_n(evm: Evm, num_bytes: int) -> None:
            if num_bytes == 0:
                charge_gas(evm, GAS_BASE)
            else:
                charge_gas(evm, GAS_VERY_LOW)
            data_to_push = U256.from_be_bytes(buffer_read(evm.code, U256(evm.pc + Uint(1)), U256(num_bytes)))
            stack.push(evm.stack, data_to_push)
            evm.pc += Uint(1) + Uint(num_bytes)

        def dup_n(evm: Evm, item_number: int) -> None:
            charge_gas(evm, GAS_VERY_LOW)
            if item_number >= len(evm.stack):
                raise StackUnderflowError
            data_to_duplicate = evm.stack[len(evm.stack) - 1 - item_number]
            stack.push(evm.stack, data_to_duplicate)
            evm.pc += Uint(1)

        def swap_n(evm: Evm, item_number: int) -> None:
            charge_gas(evm, GAS_VERY_LOW)
            if item_number >= len(evm.stack):
                raise StackUnderflowError
            evm.stack[-1], evm.stack[-1 - item_number] = evm.stack[-1 - item_number], evm.stack[-1]
            evm.pc += Uint(1)

            push0 = partial(push_n, num_bytes=0)
            push1 = partial(push_n, num_bytes=1)
            push2 = partial(push_n, num_bytes=2)
            push3 = partial(push_n, num_bytes=3)
            push4 = partial(push_n, num_bytes=4)
            push5 = partial(push_n, num_bytes=5)
            push6 = partial(push_n, num_bytes=6)
            push7 = partial(push_n, num_bytes=7)
            push8 = partial(push_n, num_bytes=8)
            push9 = partial(push_n, num_bytes=9)
            push10 = partial(push_n, num_bytes=10)
            push11 = partial(push_n, num_bytes=11)
            push12 = partial(push_n, num_bytes=12)
            push13 = partial(push_n, num_bytes=13)
            push14 = partial(push_n, num_bytes=14)
            push15 = partial(push_n, num_bytes=15)
            push16 = partial(push_n, num_bytes=16)
            push17 = partial(push_n, num_bytes=17)
            push18 = partial(push_n, num_bytes=18)
            push19 = partial(push_n, num_bytes=19)
            push20 = partial(push_n, num_bytes=20)
            push21 = partial(push_n, num_bytes=21)
            push22 = partial(push_n, num_bytes=22)
            push23 = partial(push_n, num_bytes=23)
            push24 = partial(push_n, num_bytes=24)
            push25 = partial(push_n, num_bytes=25)
            push26 = partial(push_n, num_bytes=26)
            push27 = partial(push_n, num_bytes=27)
            push28 = partial(push_n, num_bytes=28)
            push29 = partial(push_n, num_bytes=29)
            push30 = partial(push_n, num_bytes=30)
            push31 = partial(push_n, num_bytes=31)
            push32 = partial(push_n, num_bytes=32)

            dup1 = partial(dup_n, item_number=0)
            dup2 = partial(dup_n, item_number=1)
            dup3 = partial(dup_n, item_number=2)
            dup4 = partial(dup_n, item_number=3)
            dup5 = partial(dup_n, item_number=4)
            dup6 = partial(dup_n, item_number=5)
            dup7 = partial(dup_n, item_number=6)
            dup8 = partial(dup_n, item_number=7)
            dup9 = partial(dup_n, item_number=8)
            dup10 = partial(dup_n, item_number=9)
            dup11 = partial(dup_n, item_number=10)
            dup12 = partial(dup_n, item_number=11)
            dup13 = partial(dup_n, item_number=12)
            dup14 = partial(dup_n, item_number=13)
            dup15 = partial(dup_n, item_number=14)
            dup16 = partial(dup_n, item_number=15)

            swap1 = partial(swap_n, item_number=1)
            swap2 = partial(swap_n, item_number=2)
            swap3 = partial(swap_n, item_number=3)
            swap4 = partial(swap_n, item_number=4)
            swap5 = partial(swap_n, item_number=5)
            swap6 = partial(swap_n, item_number=6)
            swap7 = partial(swap_n, item_number=7)
            swap8 = partial(swap_n, item_number=8)
            swap9 = partial(swap_n, item_number=9)
            swap10 = partial(swap_n, item_number=10)
            swap11 = partial(swap_n, item_number=11)
            swap12 = partial(swap_n, item_number=12)
            swap13 = partial(swap_n, item_number=13)
            swap14 = partial(swap_n, item_number=14)
            swap15 = partial(swap_n, item_number=15)
            swap16 = partial(swap_n, item_number=16)
      </code>
    </pre>

    <h3>说明：</h3>
    <ul>
      <li><strong>pop：</strong>从堆栈中移除一个元素，并更新程序计数器。</li>
      <li><strong>push_n：</strong>根据提供的字节数，将数据压入堆栈，字节数为0时压入零。</li>
      <li><strong>dup_n：</strong>将堆栈中的第n个元素复制到堆栈顶部。</li>
      <li><strong>swap_n：</strong>交换堆栈顶部元素与第n个元素。</li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'UserManual'
}
</script>

<style scoped>
.user-manual {
  padding: 40px; /* 增加整体内边距 */
  background-color: #f9f9f9; /* 添加背景颜色，使其更柔和 */
  border-radius: 8px; /* 圆角边框 */
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
}

h1 {
  font-size: 28px;
  color: #2c3e50; /* 深色标题 */
  font-weight: bold; /* 加粗标题 */
  text-align: center; /* 居中标题 */
  margin-bottom: 20px; /* 标题下方留空 */
}

h2 {
  font-size: 22px;
  color: #34495e;
  margin-top: 30px; /* 让标题之间有更多的间隔 */
  border-bottom: 2px solid #2980b9; /* 底部边框，增加层次感 */
  padding-bottom: 5px; /* 底部边框与文字间留空 */
}

h3 {
  font-size: 18px;
  color: #7f8c8d; /* 浅色子标题 */
  margin-top: 20px;
}

p {
  font-size: 16px;
  line-height: 1.8;
  color: #2c3e50; /* 主体文字颜色 */
  margin-bottom: 15px; /* 段落之间的间距 */
}

ul {
  list-style-type: disc;
  padding-left: 20px;
  margin-top: 10px;
}

li {
  font-size: 16px;
  color: #34495e; /* 列表项颜色 */
  line-height: 1.6;
  margin-bottom: 10px; /* 列表项之间留空 */
}

.el-button {
  background-color: #3498db;
  color: white;
  border-radius: 5px;
  font-weight: bold;
}

.el-button:hover {
  background-color: #2980b9; /* 悬停时颜色变化 */
}

.el-card {
  background-color: #ffffff; /* 白色卡片背景 */
  margin-bottom: 30px; /* 卡片之间的间距 */
  border-radius: 8px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* 卡片阴影 */
  padding: 20px;
}

.el-tooltip .el-progress {
  margin-top: 10px;
}

h4 {
  font-size: 16px;
  color: #2c3e50;
  text-align: center; /* 居中显示小标题 */
}

.el-progress {
  margin-top: 10px;
}

.coverage-item h4 {
  margin-bottom: 10px;
}

.el-tooltip {
  font-size: 14px;
  color: #7f8c8d;
}
.image-container {
  text-align: center; /* 使图像居中 */
  margin: 5px 0;
}

.image-container img {
  max-width: 60%; /* 确保图像在小屏幕上不会超出页面宽度 */
  height: auto;
  border-radius: 8px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
pre {
  background-color: #f4f4f4;
  padding: 15px;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  white-space: pre-wrap;
  word-wrap: break-word;
}

code {
  color: #335ee9;
}
</style>

